package com.lingo.a2b.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lingo.a2b.common.exception.BizException;
import com.lingo.a2b.common.handler.DefaultValueConverter;
import com.lingo.a2b.common.handler.ValueConvertHandler;
import com.lingo.a2b.common.loader.DynamicClassLoader;
import com.lingo.a2b.mapper.ValueConvertMapper;
import com.lingo.a2b.model.entity.ValueConvert;
import com.lingo.a2b.service.ValueConvertService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lingo
 * @since 2020-05-21
 */
@Service
public class ValueConvertServiceImpl extends ServiceImpl<ValueConvertMapper, ValueConvert> implements ValueConvertService {
    private static Logger logger = LoggerFactory.getLogger(ValueConvertServiceImpl.class);
    private static DefaultValueConverter defaultValueConverter = new DefaultValueConverter();

    @Autowired
    private DynamicClassLoader dynamicClassLoader;

    @Override
    public int registerHandler(String handlerName, byte[] clsBytes, Integer fprojectId) {
        ValueConvert valueConvert = new ValueConvert();
        valueConvert.setFprojectId(!Objects.isNull(fprojectId) ? fprojectId : ValueConvertHandler.BELONG_TO_ALL);
        valueConvert.setFname(handlerName);
        Class<?> aClass;
        try{
            aClass = dynamicClassLoader.defineClass(clsBytes);
        }catch (ClassFormatError error){
            throw new BizException("非合法字节码文件");
        }
        if (!ValueConvertHandler.class.isAssignableFrom(aClass)) {
            throw new BizException("此类没有实现 ValueConvertHandler 接口");
        }
        String className = aClass.getName();
        LambdaQueryWrapper<ValueConvert> queryWrapper = new QueryWrapper<ValueConvert>().lambda()
                .eq(ValueConvert::getFhandlerClass, className)
                .eq(ValueConvert::getFprojectId, ValueConvertHandler.BELONG_TO_ALL)
                .or()
                .ne(!Objects.isNull(fprojectId),ValueConvert::getFprojectId, ValueConvertHandler.BELONG_TO_ALL);
        ValueConvert one = this.getOne(queryWrapper);
        if (one != null) {
            throw new BizException("已存在此转换器");
        }
        valueConvert.setFhandlerClass(className);
        valueConvert.setFisTemp(true);
        dynamicClassLoader.classNameToBytes.put(className, clsBytes);
        this.save(valueConvert);
        return valueConvert.getFid();
    }


    @Override
    public ValueConvertHandler getHandlerByCode(int code){
        if (code == ValueConvertHandler.NO_CONVERT){
            return null;
        }
        LambdaQueryWrapper<ValueConvert> queryWrapper = new QueryWrapper<ValueConvert>().lambda()
                .eq(ValueConvert::getFid, code);
        ValueConvert one = this.getOne(queryWrapper, true);
        if (one == null){
            return defaultValueConverter;
        }
        String fhandlerClass = one.getFhandlerClass();
        try {
            Class<?> aClass = Class.forName(fhandlerClass,true,dynamicClassLoader);
            return ((Class<ValueConvertHandler>) aClass).newInstance();
        } catch (ClassNotFoundException e) {
            logger.error("没有找到类 {}",fhandlerClass,e);
            throw new BizException("没有找到类：" + fhandlerClass);
        } catch (IllegalAccessException | InstantiationException e) {
           logger.error("无法实例化类：{}",fhandlerClass,e);
           throw new BizException("无法实例化类： "+ fhandlerClass);
        }
    }

    @Override
    public List<ValueConvert> listByProjectId(int fprojectId) {
        QueryWrapper<ValueConvert> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(ValueConvert::getFprojectId,fprojectId)
                .or()
                .eq(ValueConvert::getFprojectId, ValueConvertHandler.BELONG_TO_ALL);
        return this.list(queryWrapper);
    }
}
